#include "blktap.h"
-int __init xlblk_init(void)
+int __init xlblktap_init(void)
{
ctrl_msg_t cmsg;
blkif_fe_driver_status_t fe_st;
return 0;
}
+#if 0 /* tap doesn't handle suspend/resume */
void blkdev_suspend(void)
{
}
memcpy(cmsg.msg, &st, sizeof(st));
ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
}
+#endif
-
-__initcall(xlblk_init);
+__initcall(xlblktap_init);
#define WPRINTK(fmt, args...) printk(KERN_WARNING "blk_tap: " fmt, ##args)
+/* -------[ state descriptors ]--------------------------------------- */
+
+#define BLKIF_STATE_CLOSED 0
+#define BLKIF_STATE_DISCONNECTED 1
+#define BLKIF_STATE_CONNECTED 2
+
/* -------[ connection tracking ]------------------------------------- */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
unsigned long mach_fas[BLKIF_MAX_SEGMENTS_PER_REQUEST];
unsigned long virt_fas[BLKIF_MAX_SEGMENTS_PER_REQUEST];
int next_free;
- int inuse; /* debugging */
} active_req_t;
typedef unsigned int ACTIVE_RING_IDX;
* for shared memory rings.
*/
-#define RING_PAGES 128
+#define RING_PAGES 3 /* Ctrl, Front, and Back */
extern unsigned long rings_vstart;
/* Connection to a single backend domain. */
extern blkif_front_ring_t blktap_be_ring;
+extern unsigned int blktap_be_evtchn;
+extern unsigned int blktap_be_state;
-/* Event channel to backend domain. */
-extern unsigned int blkif_ptbe_evtchn;
-
-/* User ring status... this will soon vanish into a ring struct. */
+/* User ring status. */
extern unsigned long blktap_ring_ok;
/* -------[ ...and function prototypes. ]----------------------------- */
/* user ring access functions: */
int blktap_write_fe_ring(blkif_request_t *req);
int blktap_write_be_ring(blkif_response_t *rsp);
-int blktap_read_fe_ring(void);
-int blktap_read_be_ring(void);
+int blktap_write_ctrl_ring(ctrl_msg_t *msg);
/* fe/be ring access functions: */
int write_resp_to_fe_ring(blkif_t *blkif, blkif_response_t *rsp);
#include "blktap.h"
-#define BLKIF_STATE_CLOSED 0
-#define BLKIF_STATE_DISCONNECTED 1
-#define BLKIF_STATE_CONNECTED 2
-
static char *blkif_state_name[] = {
[BLKIF_STATE_CLOSED] = "closed",
[BLKIF_STATE_DISCONNECTED] = "disconnected",
[BLKIF_INTERFACE_STATUS_CONNECTED] = "connected",
[BLKIF_INTERFACE_STATUS_CHANGED] = "changed",
};
-static unsigned int blkif_pt_state = BLKIF_STATE_CLOSED;
-static unsigned blkif_ptbe_irq;
-unsigned int blkif_ptbe_evtchn;
+
+static unsigned blktap_be_irq;
+unsigned int blktap_be_state = BLKIF_STATE_CLOSED;
+unsigned int blktap_be_evtchn;
/*-----[ Control Messages to/from Frontend VMs ]--------------------------*/
sring = (blkif_sring_t *)__get_free_page(GFP_KERNEL);
SHARED_RING_INIT(BLKIF_RING, sring);
FRONT_RING_INIT(BLKIF_RING, &blktap_be_ring, sring);
- blkif_pt_state = BLKIF_STATE_DISCONNECTED;
+ blktap_be_state = BLKIF_STATE_DISCONNECTED;
DPRINTK("Blkif-Passthrough-BE is now DISCONNECTED.\n");
blkif_ptbe_send_interface_connect();
}
{
int err = 0;
- blkif_ptbe_evtchn = status->evtchn;
- blkif_ptbe_irq = bind_evtchn_to_irq(blkif_ptbe_evtchn);
+ blktap_be_evtchn = status->evtchn;
+ blktap_be_irq = bind_evtchn_to_irq(blktap_be_evtchn);
- err = request_irq(blkif_ptbe_irq, blkif_ptbe_int,
+ err = request_irq(blktap_be_irq, blkif_ptbe_int,
SA_SAMPLE_RANDOM, "blkif", NULL);
if ( err ) {
WPRINTK("blkfront request_irq failed (%d)\n", err);
} else {
/* transtion to connected in case we need to do a
a partion probe on a whole disk */
- blkif_pt_state = BLKIF_STATE_CONNECTED;
+ blktap_be_state = BLKIF_STATE_CONNECTED;
}
}
{
WPRINTK(" TAP: Unexpected blkif status %s in state %s\n",
blkif_status_name[status->status],
- blkif_state_name[blkif_pt_state]);
+ blkif_state_name[blktap_be_state]);
}
static void blkif_ptbe_status(
switch ( status->status )
{
case BLKIF_INTERFACE_STATUS_CLOSED:
- switch ( blkif_pt_state )
+ switch ( blktap_be_state )
{
case BLKIF_STATE_CLOSED:
unexpected(status);
break;
case BLKIF_INTERFACE_STATUS_DISCONNECTED:
- switch ( blkif_pt_state )
+ switch ( blktap_be_state )
{
case BLKIF_STATE_CLOSED:
blkif_ptbe_disconnect();
break;
case BLKIF_INTERFACE_STATUS_CONNECTED:
- switch ( blkif_pt_state )
+ switch ( blktap_be_state )
{
case BLKIF_STATE_CLOSED:
unexpected(status);
break;
case BLKIF_INTERFACE_STATUS_CHANGED:
- switch ( blkif_pt_state )
+ switch ( blktap_be_state )
{
case BLKIF_STATE_CLOSED:
case BLKIF_STATE_DISCONNECTED:
case CMSG_BLKIF_BE:
+ /* send a copy of the message to user if wanted */
+
+ if ( (blktap_mode & BLKTAP_MODE_INTERCEPT_FE) ||
+ (blktap_mode & BLKTAP_MODE_COPY_FE) ) {
+
+ blktap_write_ctrl_ring(msg);
+ }
+
switch ( msg->subtype )
{
case CMSG_BLKIF_BE_CREATE:
ctrl_if_send_response(msg);
}
-/*-----[ All control messages enter here: ]-------------------------------*/
+/*-----[ Initialization ]-------------------------------------------------*/
void __init blkif_interface_init(void)
{
blkif_cachep = kmem_cache_create("blkif_cache", sizeof(blkif_t),
0, 0, NULL, NULL);
memset(blkif_hash, 0, sizeof(blkif_hash));
+
+ blktap_be_ring.sring = NULL;
}
spin_lock_irqsave(&active_req_lock, flags);
idx = active_req_ring[MASK_ACTIVE_IDX(active_cons++)];
ar = &active_reqs[idx];
-if (ar->inuse) WPRINTK("AR INUSE! (%lu)\n", ar->id);
-ar->inuse = 1;
spin_unlock_irqrestore(&active_req_lock, flags);
return ar;
unsigned long flags;
spin_lock_irqsave(&active_req_lock, flags);
-ar->inuse = 0;
active_req_ring[MASK_ACTIVE_IDX(active_prod++)] = ACTIVE_IDX(ar);
spin_unlock_irqrestore(&active_req_lock, flags);
}
blkif_response_t *resp_d;
active_req_t *ar;
- /* remap id, and free the active req. blkif lookup goes here too.*/
ar = &active_reqs[ID_TO_IDX(rsp->id)];
- /* WPRINTK("%3u > %3lu\n", ID_TO_IDX(rsp->id), ar->id); */
rsp->id = ar->id;
- free_active_req(ar);
resp_d = RING_GET_RESPONSE(BLKIF_RING, &blkif->blk_ring,
blkif->blk_ring.rsp_prod_pvt);
wmb();
blkif->blk_ring.rsp_prod_pvt++;
+ blkif_put(ar->blkif);
+ free_active_req(ar);
+
return 0;
}
{
blkif_request_t *req_d;
+ if ( blktap_be_state != BLKIF_STATE_CONNECTED ) {
+ WPRINTK("Tap trying to access an unconnected backend!\n");
+ return 0;
+ }
+
req_d = RING_GET_REQUEST(BLKIF_RING, &blktap_be_ring,
blktap_be_ring.req_prod_pvt);
memcpy(req_d, req, sizeof(blkif_request_t));
inline void kick_be_domain(void)
{
+ if ( blktap_be_state != BLKIF_STATE_CONNECTED )
+ return;
+
wmb(); /* Ensure that the frontend can see the requests. */
RING_PUSH_REQUESTS(BLKIF_RING, &blktap_be_ring);
notify_via_evtchn(blkif_ptbe_evtchn);
*/
ar = get_active_req();
ar->id = req_s->id;
+ blkif_get(blkif);
ar->blkif = blkif;
req_s->id = MAKE_ID(blkif->domid, ACTIVE_IDX(ar));
/* WPRINTK("%3u < %3lu\n", ID_TO_IDX(req_s->id), ar->id); */
blkif->blk_ring.sring->req_prod,
blkif->blk_ring.sring->rsp_prod);
}
- WPRINTK("BE Ring: \n--------\n");
- WPRINTK("BE: rsp_cons: %2d, req_prod_prv: %2d "
- "| req_prod: %2d, rsp_prod: %2d\n",
- blktap_be_ring.rsp_cons,
- blktap_be_ring.req_prod_pvt,
- blktap_be_ring.sring->req_prod,
- blktap_be_ring.sring->rsp_prod);
+ if (blktap_be_ring.sring != NULL) {
+ WPRINTK("BE Ring: \n--------\n");
+ WPRINTK("BE: rsp_cons: %2d, req_prod_prv: %2d "
+ "| req_prod: %2d, rsp_prod: %2d\n",
+ blktap_be_ring.rsp_cons,
+ blktap_be_ring.req_prod_pvt,
+ blktap_be_ring.sring->req_prod,
+ blktap_be_ring.sring->rsp_prod);
+ }
}
#include <linux/gfp.h>
#include <linux/poll.h>
#include <asm/pgalloc.h>
+#include <asm-xen/xen-public/io/blkif.h> /* for control ring. */
#include "blktap.h"
/* Rings up to user space. */
static blkif_front_ring_t blktap_ufe_ring;
static blkif_back_ring_t blktap_ube_ring;
+static ctrl_front_ring_t blktap_uctrl_ring;
+
+/* local prototypes */
+static int blktap_read_fe_ring(void);
+static int blktap_read_be_ring(void);
/* -------[ blktap vm ops ]------------------------------------------- */
static int blktap_open(struct inode *inode, struct file *filp)
{
blkif_sring_t *sring;
+ ctrl_sring_t *csring;
if ( test_and_set_bit(0, &blktap_dev_inuse) )
return -EBUSY;
printk(KERN_ALERT "blktap open.\n");
+
+ /* Allocate the ctrl ring. */
+ csring = (ctrl_sring_t *)get_zeroed_page(GFP_KERNEL);
+ if (csring == NULL)
+ goto fail_nomem;
+
+ SetPageReserved(virt_to_page(csring));
+
+ SHARED_RING_INIT(CTRL_RING, csring);
+ FRONT_RING_INIT(CTRL_RING, &blktap_uctrl_ring, csring);
+
/* Allocate the fe ring. */
sring = (blkif_sring_t *)get_zeroed_page(GFP_KERNEL);
if (sring == NULL)
- goto fail_nomem;
+ goto fail_free_ctrl;
SetPageReserved(virt_to_page(sring));
DPRINTK(KERN_ALERT "blktap open.\n");
return 0;
+
+ fail_free_ctrl:
+ free_page( (unsigned long) blktap_uctrl_ring.sring);
fail_free_fe:
free_page( (unsigned long) blktap_ufe_ring.sring);
printk(KERN_ALERT "blktap closed.\n");
/* Free the ring page. */
+ ClearPageReserved(virt_to_page(blktap_uctrl_ring.sring));
+ free_page((unsigned long) blktap_uctrl_ring.sring);
+
ClearPageReserved(virt_to_page(blktap_ufe_ring.sring));
free_page((unsigned long) blktap_ufe_ring.sring);
return 0;
}
+/* Note on mmap:
+ * remap_pfn_range sets VM_IO on vma->vm_flags. In trying to make libaio
+ * work to do direct page access from userspace, this ended up being a
+ * problem. The bigger issue seems to be that there is no way to map
+ * a foreign page in to user space and have the virtual address of that
+ * page map sanely down to a mfn.
+ * Removing the VM_IO flag results in a loop in get_user_pages, as
+ * pfn_valid() always fails on a foreign page.
+ */
static int blktap_mmap(struct file *filp, struct vm_area_struct *vma)
{
int size;
/* not sure if I really need to do this... */
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ DPRINTK("Mapping ctrl_ring page %lx.\n", __pa(blktap_uctrl_ring.sring));
+ if (remap_pfn_range(vma, vma->vm_start,
+ __pa(blktap_uctrl_ring.sring) >> PAGE_SHIFT,
+ PAGE_SIZE, vma->vm_page_prot)) {
+ WPRINTK("ctrl_ring: remap_pfn_range failure!\n");
+ }
+
+
DPRINTK("Mapping be_ring page %lx.\n", __pa(blktap_ube_ring.sring));
- if (remap_page_range(vma, vma->vm_start,
- __pa(blktap_ube_ring.sring),
+ if (remap_pfn_range(vma, vma->vm_start + PAGE_SIZE,
+ __pa(blktap_ube_ring.sring) >> PAGE_SHIFT,
PAGE_SIZE, vma->vm_page_prot)) {
- WPRINTK("be_ring: remap_page_range failure!\n");
+ WPRINTK("be_ring: remap_pfn_range failure!\n");
}
DPRINTK("Mapping fe_ring page %lx.\n", __pa(blktap_ufe_ring.sring));
- if (remap_page_range(vma, vma->vm_start + PAGE_SIZE,
- __pa(blktap_ufe_ring.sring),
+ if (remap_pfn_range(vma, vma->vm_start + ( 2 * PAGE_SIZE ),
+ __pa(blktap_ufe_ring.sring) >> PAGE_SHIFT,
PAGE_SIZE, vma->vm_page_prot)) {
- WPRINTK("fe_ring: remap_page_range failure!\n");
+ WPRINTK("fe_ring: remap_pfn_range failure!\n");
}
-
+
blktap_vma = vma;
blktap_ring_ok = 1;
{
poll_wait(file, &blktap_wait, wait);
- if ( RING_HAS_UNPUSHED_REQUESTS(BLKIF_RING, &blktap_ufe_ring) ||
+ if ( RING_HAS_UNPUSHED_REQUESTS(BLKIF_RING, &blktap_uctrl_ring) ||
+ RING_HAS_UNPUSHED_REQUESTS(BLKIF_RING, &blktap_ufe_ring) ||
RING_HAS_UNPUSHED_RESPONSES(BLKIF_RING, &blktap_ube_ring) ) {
+ RING_PUSH_REQUESTS(BLKIF_RING, &blktap_uctrl_ring);
RING_PUSH_REQUESTS(BLKIF_RING, &blktap_ufe_ring);
RING_PUSH_RESPONSES(BLKIF_RING, &blktap_ube_ring);
return POLLIN | POLLRDNORM;
return 0;
}
- //target = RING_NEXT_EMPTY_REQUEST(BLKIF_RING, &blktap_ufe_ring);
target = RING_GET_REQUEST(BLKIF_RING, &blktap_ufe_ring,
blktap_ufe_ring.req_prod_pvt);
memcpy(target, req, sizeof(*req));
error = direct_remap_area_pages(blktap_vma->vm_mm,
MMAP_VADDR(ID_TO_IDX(req->id), i),
- target->frame_and_sects[0] & PAGE_MASK,
+ target->frame_and_sects[i] & PAGE_MASK,
PAGE_SIZE,
blktap_vma->vm_page_prot,
ID_TO_DOM(req->id));
/* No test for fullness in the response direction. */
- //target = RING_NEXT_EMPTY_RESPONSE(BLKIF_RING, &blktap_ube_ring);
target = RING_GET_RESPONSE(BLKIF_RING, &blktap_ube_ring,
blktap_ube_ring.rsp_prod_pvt);
memcpy(target, rsp, sizeof(*rsp));
return 0;
}
-int blktap_read_fe_ring(void)
+static int blktap_read_fe_ring(void)
{
/* This is called to read responses from the UFE ring. */
if (blktap_mode & BLKTAP_MODE_INTERCEPT_FE) {
/* for each outstanding message on the UFEring */
- //RING_FOREACH_RESPONSE(BLKIF_RING, &blktap_ufe_ring, prod, resp_s) {
rp = blktap_ufe_ring.sring->rsp_prod;
rmb();
return 0;
}
-int blktap_read_be_ring(void)
+static int blktap_read_be_ring(void)
{
/* This is called to read requests from the UBE ring. */
if (blktap_mode & BLKTAP_MODE_INTERCEPT_BE) {
/* for each outstanding message on the UFEring */
- //RING_FOREACH_REQUEST(BLKIF_RING, &blktap_ube_ring, prod, req_s) {
rp = blktap_ube_ring.sring->req_prod;
rmb();
for ( i = blktap_ube_ring.req_cons; i != rp; i++ )
return 0;
}
+
+int blktap_write_ctrl_ring(ctrl_msg_t *msg)
+{
+ ctrl_msg_t *target;
+
+ if ( ! blktap_ring_ok ) {
+ DPRINTK("blktap: be_ring not ready for a request!\n");
+ return 0;
+ }
+
+ /* No test for fullness in the response direction. */
+
+ target = RING_GET_REQUEST(CTRL_RING, &blktap_uctrl_ring,
+ blktap_uctrl_ring.req_prod_pvt);
+ memcpy(target, msg, sizeof(*msg));
+
+ blktap_uctrl_ring.req_prod_pvt++;
+
+ /* currently treat the ring as unidirectional. */
+ blktap_uctrl_ring.rsp_cons = blktap_uctrl_ring.sring->rsp_prod;
+
+ return 0;
+
+}
+
/* -------[ blktap module setup ]------------------------------------- */
static struct miscdevice blktap_miscdev = {